﻿using AutoMapper;
using AutoMapper.Configuration.Conventions;
using HamcoWcs.Contract;
using HamcoWcs.Contract.ContractCommon;
using HamcoWcs.Contract.ContractMainTask;
using HamcoWcs.Contract.ContractMainTask.IMainTaskParsers;
using HamcoWcs.Contract.ContractMes;
using HamcoWcs.Contract.ContractPcon;
using HamcoWcs.DAL;
using HamcoWcs.Entitys.MainTaskBaks;
using HamcoWcs.Entitys.MainTasks;
using HamcoWcs.Entitys.PalletInfos;
using HamcoWcs.Entitys.PathInfos;
using HamcoWcs.Entitys.WcsLocations;
using HamcoWcs.Models.Common;
using HamcoWcs.Models.Common.Enums;
using HamcoWcs.Models.Devices;
using HamcoWcs.Models.EdgeInfos;
using HamcoWcs.Models.Exceptions;
using HamcoWcs.Models.ForeEndModels.UITasks;
using HamcoWcs.Models.TibcoMessage;
using HamcoWcs.Models.TibcoMessage.Items;
using HamcoWcs.Service.Common;
using HamcoWcs.Service.Mes.Parsers;
using HamcoWcs.Workers.RouteWorkers;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Xml;
using static Org.BouncyCastle.Math.EC.ECCurve;

namespace HamcoWcs.Service.MainTasks
{
    [AutoInject(typeof(IBaseMainTaskService), InjectType.Scope)]
    [DisallowConcurrentExecution]
    public partial class BaseMainTaskService : ScopeServiceBase, IBaseMainTaskService
    {
        private void CalcPriority(MainTask mainTask)
        {
            int fp = 0;
            int tp = 0;

            var fnode = _asrs.Nodes.FirstOrDefault(x => x.NodeName == mainTask.SrcMachine);
            if (fnode != null) { fp = fnode.FPriority; }
            var tnode = _asrs.Nodes.FirstOrDefault(x => x.NodeName == mainTask.DesMachine);
            if (tnode != null) { tp = tnode.TPriority; }

            mainTask.SrcPriority = fp;
            mainTask.DesPriority = tp;

            if (string.IsNullOrEmpty(mainTask.Priority))
            {
                mainTask.Priority = "60";
            }
            if(mainTask.MainTaskType == EnumMainTaskType.LocMoveTask.ToString())
                mainTask.Priority = "14";
            else if(mainTask.SrcMachine == "CJMCV300" || mainTask.SrcMachine == "CJMCV700")
                mainTask.Priority = "11";
            _wcsDbContext.SaveChanges();
        }


        //创建子任务
        public void CreatSubTask(MainTask mainTask)
        {
            if (!RouteWorker.ASRSInitFlag) return;
            var message = _wcsDbContext.MesMsgQueues.FirstOrDefault(x => x.TransactionId == mainTask.TransactionId);

            try
            {
                if(!CheckStationMode(mainTask)) return;
                CalcPriority(mainTask);
                if (!CheckDevice(mainTask)) return;
                GenerateSubTask(mainTask);
                if (message != null)
                {
                    try
                    {
                        var res = XmlHelper.SetJobReply(message.Content);
                        message.Return = XmlHelper.SetXmlNodeText(res, "RETURNCODE", "0");
                        message.Status = (int)EnumMesMsgStatus.WcsExcuted;
                    }
                    catch (Exception)
                    {

                    }
                }

                _wcsDbContext.SaveChanges();
            }
            catch (WcsRunException ex)
            {
                if (message != null)
                {
                    var res = XmlHelper.SetJobReply(message.Content);
                    message.Return = XmlHelper.SetNGReturn(res, ex.Code.ToString(), ex.Message);
                    message.Status = (int)EnumMesMsgStatus.WcsExcuted;
                    _wcsDbContext.SaveChanges();
                }
                mainTask.TaskStatus = EnumMainTaskStatus.Cancel.ToString();
                _wcsDbContext.SaveChanges();
                //throw ex; // todo
            }
            catch (Exception ex)
            {
                if (message != null)
                {
                    var res = XmlHelper.SetJobReply(message.Content);
                    message.Return = XmlHelper.SetNGReturn(res, "7", "Unknown exception");
                    message.Status = (int)EnumMesMsgStatus.WcsExcuted;
                    _wcsDbContext.SaveChanges();
                }
                mainTask.TaskStatus = EnumMainTaskStatus.Cancel.ToString();
                _wcsDbContext.SaveChanges();
            }

        }

        /// <summary>
        /// 提升机设备宕机之后在线路没有切换的时候，不允许下发任务
        /// 在恢复后，有切换路线的两小时之内的任务，在完成之后，下发任务。
        /// </summary>
        /// <param name="mainTask"></param>
        /// <returns></returns>
        private bool CheckDevice(MainTask mainTask)
        {
            bool flag = true;
            bool errorFlag1 = false;
            bool errorFlag2 = false;
            try
            {

                var allowChangeRouteFlag = _baseConfigService.GetConfigValue("MACHINEDOWNALLOWREROUTEFLAG") == "1";
                if (!allowChangeRouteFlag) return flag;
                var path = _pathService.GetPath(mainTask.SrcMachine, mainTask.DesMachine);
                foreach (var node in _asrs.Nodes)
                {
                    string nn = node.NodeName;
                    if (GlobalValue.RouteNeedChangeRouteNode.Contains(nn))
                    {
                        bool s = node.MachineState == EnumMachineState.DOWN;
                        if (nn == "CJMIFB00" || nn == "CJVCVB00" || nn == "CJVCV700" || nn == "CJVCV500")
                            errorFlag1 |= s;
                        if (nn == "CJMIFC00" || nn == "CJVCVC00" || nn == "CJVCV600" || nn == "CJVCV800")
                            errorFlag2 |= s;
                    }
                }
                var nowTime = DateTime.Now.AddHours(-2);
                if (errorFlag1)
                {
                    if (path.UsedPath.Contains("B00")) flag = false;
                }
                else
                {
                    if (_wcsDbContext.MainTasks.Any(x => x.SrcMachine.Contains("CJSTW") && x.DesMachine.Contains("CJMCV") && x.Path.Contains("CJVCV800") && x.CreatedTime > nowTime))
                    {
                        if (mainTask.SrcMachine.Contains("CJMCV") && mainTask.DesMachine.Contains("CJSTW") && path.UsedPath.Contains("B00") &&  mainTask.CreatedTime > nowTime)
                        {
                            flag = false;
                        }
                    }
                    
                }
                if (errorFlag2)
                {
                    if (path.UsedPath.Contains("C00")) flag = false;
                }
                else
                {
                    if (_wcsDbContext.MainTasks.Any(x => x.SrcMachine.Contains("CJMCV") && x.DesMachine.Contains("CJSTW") && x.Path.Contains("CJVCV700") && x.CreatedTime > nowTime))
                    {
                        if (mainTask.SrcMachine.Contains("CJSTW") && mainTask.DesMachine.Contains("CJMCV") && path.UsedPath.Contains("C00") && mainTask.CreatedTime > nowTime)
                        {
                            flag = false;
                        }
                    }
                }
            }
            catch (Exception ex) 
            {
            }
            if (!flag && mainTask.ReasonCode.IsNullOrEmpty())
            {
                mainTask.ReasonCode = $"{mainTask.TaskId}有路径切换之前的任务未完成";
                _wcsDbContext.MainTasks.Update(mainTask);
                _wcsDbContext.SaveChanges();
            }
            return flag;
        }

        //private void CreateTask(MainTask mainTask)
        //{
        //    //var extent = ExtendDto.Deserlize(mainTask.Extend);
        //    //var ts = extent.TransActionId;
        //    //MesMsgQueue message = null;


        //}

        private bool CheckStationMode(MainTask mainTask) 
        {
               var stations = new List<string>() 
            {
                "CJRCV100","CJRCV200","CJRCV300","CJRCV400"
            };
            try
            {
                if (stations.Contains(mainTask.DesMachine))
                {
                    var pcon = _asrs.Pcons.FirstOrDefault(x => x.DeviceName == mainTask.DesMachine);
                    if (pcon == null)
                    {
                        _loggerService.AddWcsRunLog(mainTask.UnitId, $"{mainTask.TaskId}此次获取目的地失败");
                        return true;
                    }
                    if (pcon.WorkType != 2)
                    {
                        if (mainTask.ReasonCode.IsNullOrEmpty())
                        {
                            mainTask.ReasonCode = $"设备不是出库模式，{mainTask.TaskId}任务等待中...";
                            _wcsDbContext.MainTasks.Update(mainTask);
                            _wcsDbContext.SaveChanges();
                        }
                        return false;
                    }
                    mainTask.ReasonCode = string.Empty;
                }
               
            }
            catch (Exception ex) { }

            return true;
        }

        private void GenerateSubTask(MainTask mainTask)
        {
            if (mainTask.MainTaskType == EnumMainTaskType.InventoryTask.ToString())
            {
                var parser = _subTaskParseFactory.CreateParser(EnumSubTaskType.SrmInventoryTask);
                parser.Deal(mainTask, null);

                if (mainTask.TaskStatus == "Cancel")
                {
                    return;
                }
            }
            else if (mainTask.MainTaskType == EnumMainTaskType.LocMoveTask.ToString())
            {
                var path = _pathService.GetPath(mainTask.SrcMachine, mainTask.DesMachine)
                ?? throw new Exception($"未找到路径{mainTask.SrcMachine}-{mainTask.DesMachine}");
                var edges = _wcsDbContext.EdgeInfos.ToList();
                string usePath = path.UsedPath;
                int stype = 0;
                
                string srcZone = "";
                string desZone = "";
                if (!mainTask.SrcZone.IsNullOrEmpty())
                {
                    srcZone = mainTask.SrcZone;
                }
                else
                {
                    srcZone = _wcsDbContext.WcsLocations.FirstOrDefault(x => (x.WcsLocName == mainTask.SrcPosition || x.WmsLocName == mainTask.SrcPosition))?.ZoneName;
                }
                if (!mainTask.DesZone.IsNullOrEmpty())
                {
                    desZone = mainTask.DesZone;
                }
                else
                {
                    desZone = _wcsDbContext.WcsLocations.FirstOrDefault(x => (x.WcsLocName == mainTask.DesPosition || x.WmsLocName == mainTask.DesPosition))?.ZoneName;
                }
                if ((srcZone.Contains("Z1") || srcZone.Contains("Z2")) && (desZone.Contains("Z1") || desZone.Contains("Z2")) ||
                    (srcZone.Contains("Z1") || srcZone.Contains("Z2")) && (desZone.Contains("Z3") || desZone.Contains("Z6")) ||
                    (srcZone.Contains("Z3") || srcZone.Contains("Z6")) && (desZone.Contains("Z1") || desZone.Contains("Z2")))
                {
                    stype = 1;
                }
                else if ((srcZone.Contains("Z4") || srcZone.Contains("Z5")) || (desZone.Contains("Z4") || desZone.Contains("Z5")))
                {
                    stype = 2;
                }
                else if ((srcZone.Contains("Z3") || srcZone.Contains("Z6")) && (desZone.Contains("Z3") || desZone.Contains("Z6")))
                {
                    stype = 3;
                }
                usePath = stype switch
                {
                    1 => usePath.Replace("CJVCV200", "CJVCV100"),
                    2 => usePath.Replace("CJVCV100", "CJVCV200"),
                    3 => _pathService.TogglePath() ? usePath.Replace("CJVCV200", "CJVCV100") : usePath.Replace("CJVCV100", "CJVCV200"),
                    _ => "",
                };
                mainTask.Path = usePath;
                var paths = usePath.Split('-');
                if (paths.Length < 2)
                {
                    throw new ArgumentOutOfRangeException(nameof(paths));
                }
                for (int i = 0; i < paths.Length - 1; i++)
                {
                    var edgeName = $"{paths[i]}-{paths[i + 1]}";
                    var edgeEntity = edges.FirstOrDefault(x => x.EdgeName == edgeName);
                    var edge = _mapper.Map<EdgeInfoDto>(edgeEntity);
                    if (edge == null)
                    {
                        throw new Exception($"未找到路径{edgeName}");
                    }
                    var parser = _subTaskParseFactory.CreateParser(edge.EdgeType);
                    parser?.Deal(mainTask, edge);
                }

            }
            else
            {
                var path = _pathService.GetPath(mainTask.SrcMachine, mainTask.DesMachine)
                ?? throw new Exception($"未找到路径{mainTask.SrcMachine}-{mainTask.DesMachine}");
                mainTask.Path = path.UsedPath;
                foreach (var edge in path.EdgeDtos)
                {
                    var parser = _subTaskParseFactory.CreateParser(edge.EdgeType);
                    parser.Deal(mainTask, edge);
                }
            }
            mainTask.SubTasks[0].TaskStatus = EnumSubTaskStatus.Ready.ToString();
            mainTask.ReadyTime = DateTime.Now;
            //_loggerService.AddWcsRunLog(mainTask.SubTasks[0].UnitId, $"{mainTask.TaskId}-{mainTask.SubTasks[0].TaskSeq}子任务状态置为Ready");
            mainTask.TotalSubTaskNum = mainTask.SubTasks.Count;
            mainTask.TaskStatus = EnumMainTaskStatus.Ready.ToString();
            //_loggerService.AddWcsRunLog(mainTask.UnitId, $"{mainTask.TaskId}主任务状态置为Ready");
            _wcsDbContext.MainTasks.Update(mainTask);
        }
        private void CalcPath(MainTask mainTask)
        {
            var oldPath = mainTask.Path;
            try
            {
                if (oldPath.Contains("VCV200"))
                {
                    if (mainTask.SrcZone != null && mainTask.DesZone == null)
                    {

                    }
                }
            }
            catch (Exception ex)
            {

            }
        }

        public void DeleteMainTask(MainTask mainTask)
        {
            var mainTaskBak = _mapper.Map<MainTaskBak>(mainTask);
            _wcsDbContext.MainTaskBaks.Add(mainTaskBak);
            _wcsDbContext.SubTasks.RemoveRange(mainTask.SubTasks);
            _wcsDbContext.MainTasks.Remove(mainTask);
            //_loggerService.AddWcsRunLog(mainTask.UnitId, $"删除主任务{mainTask.TaskId}");
        }

        public void CancelMainTask(MainTask mainTask)
        {
            foreach (var subTask in mainTask.SubTasks)
            {
                if (subTask.TaskStatus == EnumSubTaskStatus.NewTask.ToString()
                 || subTask.TaskStatus == EnumSubTaskStatus.Ready.ToString())
                {
                    if (subTask.ToLoc.IsShelf())
                    {
                        var loc = _locationService.GetLocationByWcsName(subTask.ToLoc);
                        if (loc.LocStatus == (int)EnumLocStatus.In)
                        {
                            if (loc.ZoneName.Contains("Z6"))
                            {
                                loc.LocStatus = (int)EnumLocStatus.HandOff;
                                loc.Remark = $"任务取消时修改状态为中转储位{mainTask.TaskId}";
                            }
                            else
                            {
                                loc.LocStatus = (int)EnumLocStatus.Empty;
                                loc.Remark = $"任务取消时修改状态为空{mainTask.TaskId}";
                            }
                            _wcsDbContext.SaveChanges();
                        }
                    }

                    if (subTask.FromLoc.IsShelf())
                    {
                        var loc = _locationService.GetLocationByWcsName(subTask.FromLoc);
                        if (loc.LocStatus == (int)EnumLocStatus.Out)
                        {
                            if (loc.ZoneName.Contains("Z6") && !string.IsNullOrEmpty(loc.UnitId))
                            {
                                loc.LocStatus = (int)EnumLocStatus.HandOff;
                                loc.Remark = $"任务取消时修改状态为中转储位{mainTask.TaskId}";
                            }
                            else
                            {
                                loc.LocStatus = (int)EnumLocStatus.Store;
                                loc.Remark = $"任务取消时修改状态为有货{mainTask.TaskId}";
                            }
                            _wcsDbContext.SaveChanges();
                        }
                    }

                }
            }

            if (!string.IsNullOrEmpty(mainTask.UnitId))
            {
                var addr = _locationService.GetAddress(mainTask.UnitId);
                WcsLocation loc = null;
                if (addr != null)
                {
                    mainTask.CurrentMachine = addr.MachineName;
                    mainTask.CurrentPosition = addr.PositionName;
                    mainTask.CurrentType = addr.PositionType;
                    mainTask.CurrentZone = addr.ZoneName;
                    if (addr.PositionType == "SHELF")
                    {
                        loc = _locationService.GetPalletLocation(mainTask.UnitId);
                    }
                }
                string palletLocState = "";
                if (loc != null)
                {
                    palletLocState = (loc.IsLock || loc.SrmOccupyFlag) ? "BLOCKED" : "UNBLOCKED";
                }

                _mesCommunicateService.PalletTransportJobTerminatedByAGV(mainTask, palletLocState);
            }

            var mainTaskBak = _mapper.Map<MainTaskBak>(mainTask);
            _wcsDbContext.MainTaskBaks.Add(mainTaskBak);
            _wcsDbContext.SubTasks.RemoveRange(mainTask.SubTasks);
            _wcsDbContext.MainTasks.Remove(mainTask);
            _loggerService.AddWcsRunLog(mainTask.UnitId, $"取消主任务{mainTask.TaskId}");
        }

        // todo 异常结束时获取当前位置
        public void FinishMainTask(MainTask mainTask)
        {
            mainTask.CompleteTime = DateTime.Now;
            //CURRENT_JOBS.Remove(mainTask.TaskId);
            try
            { 
                if (string.IsNullOrEmpty(mainTask.OldDesMachine))
                {
                    // 正常结束 上报MES任务完成
                    _mesCommunicateService.PalletTransportJobCompleted(mainTask);
                }
                else
                {
                    if (!string.IsNullOrEmpty(mainTask.UnitId))
                    {
                        var addr = _locationService.GetAddress(mainTask.UnitId);
                        WcsLocation loc = null;
                        if (addr != null)
                        {
                            mainTask.CurrentMachine = addr.MachineName;
                            mainTask.CurrentPosition = addr.PositionName;
                            mainTask.CurrentType = addr.PositionType;
                            mainTask.CurrentZone = addr.ZoneName;
                            if (addr.PositionType == "SHELF")
                            {
                                loc = _locationService.GetPalletLocation(mainTask.UnitId);
                            }
                        }
                        string palletLocState = "";
                        if (loc != null)
                        {
                            palletLocState = (loc.IsLock || loc.SrmOccupyFlag) ? "BLOCKED" : "UNBLOCKED";
                        }

                        _mesCommunicateService.PalletTransportJobTerminatedByAGV(mainTask, palletLocState);
                    }
                }
            }
            catch (Exception ex)
            {
                _loggerService.AddSystemErrorLog("MainTaskService->PalletTransportJobCompleted:上报任务完成时发生异常");
            }

            mainTask.TaskStatus = EnumMainTaskStatus.Delete.ToString();
            //_loggerService.AddWcsRunLog(mainTask.UnitId, $"Task:{mainTask.TaskId} Completed");
        }


        public void ReportStart(MainTask mainTask)
        {
            //if (CURRENT_JOBS.ContainsKey(mainTask.TaskId)) return;
            //CURRENT_JOBS.Add(mainTask.TaskId, mainTask);

            // 没有上报需要上报给MES
            if (mainTask.IsReportStart == 0)
            {
                mainTask.StartTime = DateTime.Now;
                mainTask.IsReportStart = 1;
                PalletTransportJobStarted(mainTask);
            }

            CheckTimeout(mainTask);
        }

        /// <summary>任务开始时上报任务开始信号<br/></summary>
        private void PalletTransportJobStarted(MainTask mainTask)
        {
            if (mainTask.Sender.ToUpper() == "MES")
            {
                _mesCommunicateService.PalletTransportJobStarted(new PalletTransportJobStartedMessage(new PalletTransportJobStartedMessageBody()
                {
                    CurrentMachineName = mainTask.SrcMachine,
                    CurrentPositionName = mainTask.SrcPosition,
                    CurrentPositionType = mainTask.SrcType,
                    CurrentZoneName = mainTask.SrcZone,
                    EventUser = mainTask.SrcMachine,
                    TransferState = mainTask.SrcType == "SHELF" ? "ONEQP" : "MOVING",
                    PalletName = mainTask.UnitId,
                    TransportJobName = mainTask.TaskId
                }));
            }
            else
            {
                //var extend = ExtendDto.Deserlize(mainTask.Extend);
                //var desAddress = GetDestinationAddress(mainTask);
                _mesCommunicateService.PalletTransportJobStartedByAGV(new PalletTransportJobStartedByAGVMessage(new PalletTransportJobStartedByAGVMessageBody
                {
                    SourceMachineName = mainTask.SrcMachine,
                    SourcePositionName = mainTask.SrcPosition,
                    SourcePositionType = mainTask.SrcType,
                    SourceZoneName = mainTask.SrcZone,
                    CurrentMachineName = mainTask.SrcMachine,
                    CurrentPositionName = mainTask.SrcPosition,
                    CurrentPositionType = mainTask.SrcType,
                    CurrentZoneName = mainTask.SrcZone,
                    DestinationMachineName = mainTask.DesMachine,
                    DestinationPositionName = mainTask.DesPosition,
                    DestinationPositionType = mainTask.DesType,
                    DestinationZoneName = mainTask.DesZone,
                    PalletName = mainTask.UnitId,
                    TransportJobName = mainTask.TaskId,
                    EventUser = mainTask.SrcMachine,
                    TransferState = mainTask.SrcType == "SHELF" ? "INSTK" : "MOVING",
                    Priority = mainTask.Priority
                }));
            }
        }


        public void SetMainTaskError(MainTask task)
        {
            task.TaskStatus = EnumMainTaskStatus.Error.ToString();
            _wcsDbContext.Update(task);
            _wcsDbContext.SaveChanges();
        }




        //public MainTask GetCurrentMainTaskByPallet(string unitId)
        //{
        //    MainTask task = CURRENT_JOBS.Values.FirstOrDefault(x => x.UnitId == unitId);

        //    if (task == null)
        //    {
        //        task = _wcsDbContext.MainTasks.FirstOrDefault(x => x.UnitId == unitId);

        //        if (task != null && task.TaskStatus == EnumMainTaskStatus.OnProgress.ToString())
        //        {
        //            CURRENT_JOBS.Add(task.TaskId, task);
        //        }
        //    }

        //    return task;
        //}

        /// <summary>
        /// 判断任务是否存在
        /// </summary>
        public bool ChcekPalletTaskExists(string unitId)
        {
            return _wcsDbContext.MainTasks.Any(x => x.UnitId == unitId);
        }


        /// <summary>
        /// 创建异常出库任务
        /// </summary>
        /// <param name="create"></param>
        /// <returns></returns>
        /// <exception cref="WarningException"></exception>
        public MainTask CreateAbnormalOutboundTask(MainTaskCreate create)
        {
            if (!create.FromLoc.IsShelf()) throw new WarningException("错误的起始地");
            if (!create.ToLoc.Contains("CJRCV")) throw new WarningException("错误的目的地");

            var loc = _locationService.GetLocationByWcsName(create.FromLoc);
            var pcon = _asrs.Pcons.FirstOrDefault(x => x.MachineName == create.ToLoc && x.PortName == "02")
                ?? throw new WarningException("错误的目的地");

            if (pcon.WorkType != 2) throw new WarningException("目的地不为出库模式");
            if (!pcon.Machine.IsRunning) throw new WarningException("目的地状态不为RUN");

            var task = new MainTask()
            {
                SrcMachine = loc.ZoneName.Substring(0, loc.ZoneName.Length - 2),
                SrcPosition = loc.WcsLocName,
                SrcType = "SHELF",
                SrcZone = loc.ZoneName,
                DesMachine = create.ToLoc,
                DesPosition = "02",
                DesType = "PORT",
                DesZone = "",
                Sender = "WCS",
                TaskId = $"{DateTime.Now:yyyyMMddHHmmssfff}-{create.UnitId}-WCS",
                UnitId = create.UnitId,
                Priority = GlobalValue.DEFAULT_TASK_PRIORITY,
                TaskStatus = EnumMainTaskStatus.NewTask.ToString(),
                MainTaskType = EnumMainTaskType.AbnormalOutboundTask.ToString(),
                CreatedTime = DateTime.Now,
            };

            _wcsDbContext.Set<MainTask>().Add(task);
            _wcsDbContext.SaveChanges();
            return task;
        }


        public MainTask CreateTaskByWcs(MainTaskCreate create)
        {
            var fAddr = GetTargetAddress(create.FromLoc);
            var tAddr = GetTargetAddress(create.ToLoc, false);

            var path = _pathService.GetPath(fAddr.MachineName, tAddr.MachineName)
                ?? throw new WarningException("未找到该路径");

            var task = new MainTask()
            {
                SrcMachine = fAddr.MachineName,
                SrcPosition = fAddr.PositionName,
                SrcType = fAddr.PositionType,
                SrcZone = fAddr.ZoneName,
                DesMachine = tAddr.MachineName,
                DesPosition = tAddr.PositionName,
                DesType = tAddr.PositionType,
                DesZone = tAddr.ZoneName,
                Sender = "WCS",
                TaskId = $"{DateTime.Now:yyyyMMddHHmmssfff}-{create.UnitId}-WCS",
                UnitId = create.UnitId,
                Priority = GlobalValue.DEFAULT_TASK_PRIORITY,
                TaskStatus = EnumMainTaskStatus.NewTask.ToString(),
                MainTaskType = GetMainTaskType(fAddr.PositionType, tAddr.PositionType),
                CreatedTime = DateTime.Now,
                Path = path.UsedPath
            };
            _wcsDbContext.Set<MainTask>().Add(task);
            _wcsDbContext.SaveChanges();
            _mesCommunicateService.CreateTransportJobByWCS(task);
            return task;
        }




        public void CreateTaskByMes(string message)
        {
            var msg = XmlHelper.Deserialize<PalletRequestTransportJobMessage>(message);
            var req = msg.Body;
            var materialInfo = XmlHelper.GetMaterialInfo(message);
            // todo 存储物料信息
            var task = new MainTask()
            {
                TransactionId = msg.HEADER.TRANSACTIONID,
                SrcMachine = req.SourceMachineName,
                SrcPosition = req.SourcePositionName,
                SrcType = req.SourcePositionType,
                SrcZone = req.SourceZoneName,
                DesMachine = req.DestinationMachineName,
                DesPosition = req.DestinationPositionName,
                DesType = req.DestinationPositionType,
                DesZone = req.DestinationZoneName,
                Sender = "MES",
                TaskId = req.TransportJobName,
                UnitId = req.PalletName,
                Priority = req.Priority,
                TaskStatus = EnumMainTaskStatus.NewTask.ToString(),
                MainTaskType = GetMainTaskType(req.SourcePositionType, req.DestinationPositionType),
                CreatedTime = DateTime.Now,
                MaterialInfo = JsonConvert.SerializeObject(materialInfo)
            };

            if (task.MainTaskType == EnumMainTaskType.LocMoveTask.ToString() || string.IsNullOrEmpty(task.DesPosition))
            {
                var zone = task.DesZone;
                var tloc = _locationService.GetEmptyLocationByZone(zone)
                    ?? throw new MESJobException(50, "Not fount empty shelf in destination zone");


                tloc.LocStatus = (int)EnumLocStatus.In;
                task.DesPosition = tloc.WcsLocName;
            }


            var palletInfo = _wcsDbContext.Set<PalletInfo>().FirstOrDefault(x => x.UnitId == req.PalletName);
            if (palletInfo == null)
            {
                palletInfo = new PalletInfo()
                {
                    UnitId = req.PalletName,
                    MaterialInfo = JsonConvert.SerializeObject(materialInfo)
                };
                _wcsDbContext.Set<PalletInfo>().Add(palletInfo);
            }
            else
            {
                palletInfo.MaterialInfo = JsonConvert.SerializeObject(materialInfo);
            }

            //var settingCode = XmlHelper.GetXPathText(message, "//PALLETSETTINGCODE");
            GetSettingCode(message, out string settingCode, out string size);
            palletInfo.SettingCode = settingCode;
            palletInfo.Size = size;

            try
            {
                if (PACKINGMACHINENAMES.Contains(req.SourceMachineName))
                {
                    if (materialInfo.MaterialCount == 6)
                    {
                        palletInfo.PalletType = "PRODUCT";
                    }
                    else
                    {
                        palletInfo.PalletType = "FULL";
                    }
                    if (materialInfo.MaterialCount == 0)
                    {
                        palletInfo.PalletType = "PALLET";
                    }
                   
                }
            }
            catch (Exception)
            {
            }

            // 获取单号
            var orderNumber = XmlHelper.GetXPathText(message, "//RSNUM");
            if (!string.IsNullOrEmpty(orderNumber))
            {
                palletInfo.OrderNumber = orderNumber;
            }


            _wcsDbContext.MainTasks.Add(task);
            _wcsDbContext.SaveChanges();
        }


        private void GetSettingCode(string message, out string settingCode, out string size)
        {
            settingCode = XmlHelper.GetXPathText(message, "//PALLETSETTINGCODE");
            size = "UNK";

            switch (settingCode)
            {
                case "3255": size = "43"; break;
                case "6500": size = "65"; break;
                case "7500": size = "75"; break;
                case "8898": size = "85"; break;
                default: break;
            }

        }

        public string GetMainTaskType(string f, string t)
        {
            EnumMainTaskType taskType;
            if (f.Equals("shelf", StringComparison.OrdinalIgnoreCase))
            {
                if (t.Equals("shelf", StringComparison.OrdinalIgnoreCase))
                {
                    taskType = EnumMainTaskType.LocMoveTask;
                }
                else
                {
                    taskType = EnumMainTaskType.OutboundTask;
                }
            }
            else
            {
                if (t.Equals("shelf", StringComparison.OrdinalIgnoreCase))
                {
                    taskType = EnumMainTaskType.InboundTask;
                }
                else
                {
                    taskType = EnumMainTaskType.PortMoveTask;
                }
            }

            return taskType.ToString();
        }

        public MachineAddressDto GetTargetAddress(string target, bool isFrom = true)
        {
            var addr = new MachineAddressDto();

            if (target.IsShelf())
            {
                var loc = _wcsDbContext.WcsLocations.FirstOrDefault(x => x.WcsLocName == target && x.LocType == "shelf");

                if (loc == null) throw new WarningException($"未找到对应货架[{target}]");
                if (loc.IsLock) throw new WarningException($"货位[{target}]已锁定，无法操作");
                if (loc.SrmOccupyFlag) throw new WarningException($"货位[{target}]堆垛机占位，无法操作");

                if (isFrom)
                {
                    if (loc.LocStatus != (int)EnumLocStatus.Store && !loc.ZoneName.Contains("Z6")) throw new WarningException($"货位[{target}]不为存储状态，无法出库");
                    loc.LocStatus = (int)EnumLocStatus.Out;
                }
                else
                {
                    if (loc.LocStatus != (int)EnumLocStatus.Empty) throw new WarningException($"货位[{target}]不为空状态，无法入库");
                    loc.LocStatus = (int)EnumLocStatus.In;
                }

                addr.MachineName = loc.ZoneName.Substring(0, loc.ZoneName.Length - 2);
                addr.PositionName = target;
                addr.ZoneName = loc.ZoneName;
                addr.PositionType = "SHELF";
            }
            else if (target.IsZone())
            {
                var loc = _locationService.GetEmptyLocation(target);
                if (loc == null) throw new Exception($"区域[{target}]未找到空货架");
                addr.MachineName = loc.ZoneName.Substring(0, loc.ZoneName.Length - 2);
                addr.PositionName = loc.WcsLocName;
                addr.ZoneName = loc.ZoneName;
                addr.PositionType = "SHELF";
            }
            else
            {
                addr.MachineName = target;
                addr.PositionName = "01";
                addr.ZoneName = "";
                addr.PositionType = "PORT";
            }


            return addr;
        }

        public void CheckCreateTimeout(MainTask mainTask)
        {
            var now = DateTime.Now;
            int timeout = 30;
            try
            {
                _baseConfigService.TryGetConfigValue("TASK_TIMEOUT_THRESHOLD", out string value);
                if (!value.IsNullOrEmpty() && value != "0")
                {
                    timeout = int.Parse(value);
                }
                if (mainTask.CreatedTime.AddMinutes(timeout) < now)
                {
                    if (mainTask.IsTimeout == 0) mainTask.IsTimeout = 1;
                }
                else
                {
                    mainTask.IsTimeout = 0;
                }
            }
            catch (Exception ex)
            {
                //_loggerService.AddSystemErrorLog($"CheckTimeout error : {ex.Message}");
            }
        }

        public void CheckTimeout(MainTask mainTask)
        {
            var now = DateTime.Now;
            var interval = GlobalValue.G_CONFIG.TaskPriorityIncInterval;
            if (mainTask.LastPriorityUpdateTime.AddMinutes(interval) < now)
            {
                try
                {
                    int priority = int.Parse(mainTask.Priority);
                    if (priority < 99 && mainTask.MainTaskType != EnumMainTaskType.LocMoveTask.ToString())
                    {
                        mainTask.Priority = (priority + 1).ToString();
                        _mesCommunicateService.PalletTransportPriorityChanged(mainTask.TaskId, mainTask.Priority);
                        mainTask.LastPriorityUpdateTime = DateTime.Now;
                    }
                }
                catch (Exception)
                {

                }
            }

        }



        #region Static
        //static BaseMainTaskService()
        //{
        //    CURRENT_JOBS = new Dictionary<string, MainTask>();
        //}

        //public static Dictionary<string, MainTask> CURRENT_JOBS { get; set; }



        #endregion

        #region Constructor

        private readonly IPathService _pathService;
        private readonly ISubTaskParseFactory _subTaskParseFactory;
        private readonly ILoggerService _loggerService;
        private readonly IMesCommunicateService _mesCommunicateService;
        private readonly IPalletService _palletService;
        private readonly ILocationService _locationService;
        private readonly IPconBaseService _pconService;
        private readonly IBaseConfigService _baseConfigService;
        private readonly AutomaticStorageInfo _asrs;
        public BaseMainTaskService(AutomaticStorageInfo asrs, IMapper mapper, WcsDbContext wcsDbContext, IPathService pathService
         , ISubTaskParseFactory subTaskParseFactory, ILoggerService loggerService,
            IMesCommunicateService mesCommunicateService, ILocationService locationService,
            IPconBaseService pconService, IPalletService palletService, IBaseConfigService baseConfigService)
            : base(wcsDbContext, mapper)
        {
            _pathService = pathService;
            _subTaskParseFactory = subTaskParseFactory;
            _loggerService = loggerService;
            _mesCommunicateService = mesCommunicateService;
            _locationService = locationService;
            _pconService = pconService;
            _palletService = palletService;
            _asrs = asrs;
            _baseConfigService = baseConfigService;
        }

        #endregion
        private static List<string> PACKINGMACHINENAMES = new List<string>()
        {
            "CJMCV300",
            "CJMCV700",
        };
    }

}
